using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace Arroguella.Utilities
{
    /// <summary>
    /// Randomly chooses an element from a collection of elements based on that element's probability.
    /// </summary>
    public class ProbabilityChooser<T>
    {
        #region Constructors

        public ProbabilityChooser(Dictionary<T, int> collection)
        {
            Debug.Assert(collection != null, "A collection in ProbabilityChooser is null.");
            this.collection = collection;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Chooses one of the elements within its collection randomly,
		/// but based on its probability, and returns it.
        /// This does not remove the element from the list.
        /// </summary>
        public virtual T Choose()
        {
			int total = 0;
			foreach(KeyValuePair<T, int> entry in collection)
			{
				total += entry.Value;
			}
			
            int choice = random.Next(0, total+1);
			
			int min = 0, max = 0;
			foreach(KeyValuePair<T, int> element in collection)
			{
				min = max;
				max += element.Value;
				
				if(choice >= min && choice < max)
				{
					return element.Key;
				}
			}

            return default(T);
        }

        /// <summary>
        /// Chooses one of the elements within its collection randomly,
		/// but based on its probability, and returns its ToString() method.
        /// This does not remove the element from the list.
        /// </summary>
        public virtual string ChooseAsString()
        {
            return Choose().ToString();
        }

        public void Add(T value, int probability)
        {
            collection.Add(value, probability);
        }

        public void Add(Dictionary<T, int> values)
        {
            foreach (KeyValuePair<T, int> value in values)
            {
                collection.Add(value.Key, value.Value);
            }
        }

        public void Remove(T key)
        {
            collection.Remove(key);
        }

        #endregion

        #region Properties

        private readonly Dictionary<T, int> collection;

        private readonly Random random = new Random();

        #endregion
    }
}